贪心算法区间图着色问题

问题来自算法导论十六章,使用尽可能少的教室对一系列活动进行调度。
思路,把能兼容的活动放在以一个教室。
先把所有活动按结束时间递增的顺序排列,方便以后的循环。选取快速排序,期望时间复杂度为nlgn,最坏为n^2.快排我都有点忘记了,但是看了一下算法导论的图就秒懂了,可见学算法结合图形还是很重要的事情。
循环活动,把每个活动往教室里填,看活动是否与教室里已有的活动兼容(也就是开始时间是否比最后一个活动的结束时间更晚),如果兼容,就填进教室里去,如果不兼容,就新开一个教室存放该活动。继续循环。

代码如下,注释很详细。参考了一位博主的代码,现在找不到他那个页面了,见谅…该博主用了结构体,这个问题确实很适合用结构体,在一个活动中有开始时间结束时间然后表状态,记录选择。不用去定义很多数组再一一对应。学习学习



#include "stdafx.h"
#include<stdio.h>
# define N 100

struct Activity
{
	int number;            //活动编号
	int begin;           //活动开始时间
	int end;            //活动结束时间
	bool flag;          //此活动是否被选择
	int roomnum;      //此活动在哪间教室举行
};


//对于活动集,按照结束时间递增排序,使用快速排序
void quicksort(Activity *a, int p, int r)
{
	if (p < r)
	{
		int i = p- 1,j=p;
		Activity aa = a[r];
		while (j < r)                              //这个while循环是在将数组划分为小于最后一个元素,大于最后一个元素和最后一个元素三部分。
		{
			if (a[j].end <= aa.end)                 
			{
				i++;                            //i总是指向第一个区域的最后一个元素,然后i++去占领新的位置。j始终指向第二个区域的最后一个元素的下一个元素,也就是即将归类的新元素
				Activity t = a[i];
				a[i] = a[j];
				a[j] = t;
			}
			j++;
		}
		Activity t = a[r];               //以下三行的交换是为了把最后一个元素提到他应该有的位置
		a[r] = a[i + 1];
		a[i + 1] = t;
		quicksort(a, p, i);
		quicksort(a, i + 1, r);
	}
}


int select_room(Activity *a, int *time, int n)
{
	int i = 1, j = 1;
	                        //下面初始化数据,把第一个活动安排了,然后循环从第二个活动开始
	int sumroom=1;        //已经占用的教室,计算然后返回最终值
	int sumact=1;           //已经被选择的活动,初始化为1
	time[1] = a[0].end;      //初始化教室1的最后一个活动的结束时间为活动1的结束时间
	a[0].roomnum = 1;         //将第一个活动占用的教室初始化为教室1
	for (i = 1; i < n; i++)                   //遍历i个活动
	{ 
		 for(j=1;j<=sumroom;j++)                    //遍历j个教室,把活动i放进哪个教室
			if (a[i].begin >= time[j] && (!a[i].flag))          //活动i开始的时间比教室j最后一个活动的结束时间晚,且活动i没有被规划过。那么就应该吧活动i划入教室j
			{                                                   //进行一波更新
				a[i].roomnum = j;
				a[i].flag = true;
				time[j] = a[i].end;
				sumact++;
			}
		 if (sumact < n&&i == n - 1)             //已经把一间教室能加入的活动搞完了,活动i不能已有加入教室,那么它就自己新开一间教室
		 {
			 i = 0;                              //控制重新遍历的条件
			 sumroom++;
		 }
	}
	return sumroom;
}

int main()
{
	Activity a[N];          //定义一个结构体
	int time[N];            //time 用于记录某个教室里面末尾活动的结束时间,方便与下一个活动的开始时间比较
	int n,i=0,j;                  //输入的活动个数
	int sum;
	int k = 0;
	printf("输入活动个数:\n");
	scanf_s("%d", &n);
	for (i = 0; i < n; i++)
	{
		time[i + 1] = 0;
		a[i].number = i + 1;
		a[i].flag = false;
		a[i].roomnum = 0;      
		printf("输入活动%d的开始时间:", ++k);
		scanf_s("%d", &a[i].begin);
		printf("输入活动%d的结束时间:", k);
		scanf_s("%d", &a[i].end);
		
	}
	quicksort(a, 0, n - 1);
	sum = select_room(a, time, n);
	printf("所占教室总数目是:%d\n", sum);
	for (i = 0; i < n; i++)
		printf("活动%d在教室%d中\n", a[i].number, a[i].roomnum);
}
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值